package net.gdface.json;

import java.lang.reflect.Type;
import java.util.Calendar;
import java.util.Date;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.JSONLexer;
import com.alibaba.fastjson.parser.JSONScanner;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import static net.gdface.utils.DateSupport.parseAsDate;
import static net.gdface.utils.DateSupport.castToDate;

/**
 * 日期类型FASTJSON反序列化实现，
 * 相比默认的反序列化器 {@link com.alibaba.fastjson.serializer.DateCodec}  支持更多日期格式
 * @author guyadong
 * @since 2.8.8
 */
public class FastjsonDateDeserializer implements ObjectDeserializer {
	public static final FastjsonDateDeserializer INSTANCE = new FastjsonDateDeserializer();
    @Override
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
        JSONLexer lexer = parser.lexer;
        if(!(type instanceof Class) || !(Date.class.isAssignableFrom((Class)type) || Calendar.class.isAssignableFrom((Class)type))) {
        	throw new IllegalArgumentException("type required Date or Calendar");
        }
        switch(lexer.token()) {
        case JSONToken.LITERAL_INT:{
            long millis = lexer.longValue();
            lexer.nextToken(JSONToken.COMMA);
            try {
            	return (T) castToDate(millis,(Class)type);
			} catch (Exception e) {
				throw new JSONException(e.getMessage(),e);
			}
        }
        case JSONToken.LITERAL_STRING:{
            String strVal = lexer.stringVal();
            lexer.nextToken(JSONToken.COMMA);

            try(JSONScanner iso8601Lexer = new JSONScanner(strVal)){
            	if (iso8601Lexer.scanISO8601DateIfMatch(false)) {
            		Calendar calendar = iso8601Lexer.getCalendar();
            		return (T) castToDate(calendar,(Class)type);
            	}else {
					Object parsed = parseAsDate(strVal, (Class)type,0,1,2,3,4);
					if(parsed != null) {
						return (T) parsed;
					}
					throw new JSONException("FAIL parse date: "+strVal);
				}
            }
        }
        case JSONToken.NULL:
        	lexer.nextToken();
            return null;
        default:
        	throw new JSONException("parse error");
        }
    }
    @Override
    public int getFastMatchToken() {
        return JSONToken.LITERAL_INT;
    }
}
